<!DOCTYPE HTML PUBLIC "-//ORA//DTD CD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>[Chapter 10] 10.8 Defining a Bean Customizer</TITLE>
<META NAME="author" CONTENT="David Flanagan">
<META NAME="date" CONTENT="Thu Jul 31 15:57:54 1997">
<META NAME="form" CONTENT="html">
<META NAME="metadata" CONTENT="dublincore.0.1">
<META NAME="objecttype" CONTENT="book part">
<META NAME="otheragent" CONTENT="gmat dbtohtml">
<META NAME="publisher" CONTENT="O'Reilly &amp; Associates, Inc.">
<META NAME="source" CONTENT="SGML">
<META NAME="subject" CONTENT="Java">
<META NAME="title" CONTENT="Java in a Nutshell">
<META HTTP-EQUIV="Content-Script-Type" CONTENT="text/javascript">
</HEAD>
<body vlink="#551a8b" alink="#ff0000" text="#000000" bgcolor="#FFFFFF" link="#0000ee">

<DIV CLASS=htmlnav>
<H1><a href='index.htm'><IMG SRC="gifs/smbanner.gif"
     ALT="Java in a Nutshell" border=0></a></H1>
<table width=515 border=0 cellpadding=0 cellspacing=0>
<tr>
<td width=172 align=left valign=top><A HREF="ch10_07.htm"><IMG SRC="gifs/txtpreva.gif" ALT="Previous" border=0></A></td>
<td width=171 align=center valign=top><B><FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">Chapter 10<br>Java Beans</FONT></B></TD>
<td width=172 align=right valign=top><A HREF="ch10_09.htm"><IMG SRC="gifs/txtnexta.gif" ALT="Next" border=0></A></td>
</tr>
</table>

&nbsp;
<hr align=left width=515>
</DIV>
<DIV CLASS=sect1>
<h2 CLASS=sect1><A CLASS="TITLE" NAME="JNUT2-CH-10-SECT-8">10.8 Defining a Bean Customizer</A></h2>

<P CLASS=para>
<A NAME="CH10.JAVABEANS.AP4"></A><A NAME="CH10.CUSTOMIZER.C1"></A>A bean may want to provide some way for the user of a
beanbox program to customize its properties other than by setting
them one at a time.  A bean can do this by
creating a <tt CLASS=literal>Customizer</tt> class for itself, and
registering the customizer class with the
<tt CLASS=literal>BeanDescriptor</tt> object returned by its
<tt CLASS=literal>BeanInfo</tt> class, as we saw in
<A HREF="ch10_05.htm#JNUT2-CH-10-EX-5">Example 10.5</A>.

<P CLASS=para>
A customizer must be some kind of AWT component that is
suitable for display in a dialog box created by the beanbox.
Therefore, a customizer class is typically a subclass of
<tt CLASS=literal>Panel</tt>.  In addition, a customizer must implement the
<tt CLASS=literal>Customizer</tt> interface.  This interface consists of
methods for adding and removing property change event
listeners and a <tt CLASS=literal>setObject()</tt> method that the beanbox
calls to tell the customizer what bean object it is
customizing.  Whenever the user makes a change to the bean
through the customizer, the customizer should send a
<tt CLASS=literal>PropertyChangeEvent</tt> to any interested listeners.
Finally, like a property editor, a customizer must have a
no-argument constructor, so it can easily be instantiated
by a beanbox.

<P CLASS=para>
<A HREF="ch10_08.htm#JNUT2-CH-10-EX-8">Example 10.8</A>
shows a customizer for our <tt CLASS=literal>YesNoDialog</tt> bean.  This
customizer displays a panel that has the same layout as a
<tt CLASS=literal>YesNoDialog</tt>, but it substitutes a 
<tt CLASS=literal>TextArea</tt>
object for the message display and three
<tt CLASS=literal>TextField</tt> objects for the three buttons that the
dialog can display.  These text entry areas allow the user
to enter values for the <tt CLASS=literal>message</tt>, <tt CLASS=literal>yesLabel</tt>,
<tt CLASS=literal>noLabel</tt>, and <tt CLASS=literal>cancelLabel</tt>
properties.
<A HREF="ch10_08.htm#JNUT2-CH-10-FIG-3">Figure 10.3</A>
shows this customizer panel displayed within a dialog box
created by the <I CLASS=emphasis>beanbox</I> program.  Again, note that the
<b>Done</b> button is part of the <I CLASS=emphasis>beanbox</I> dialog, not
part of the customizer itself.

<DIV CLASS=figure>
<h4 CLASS=figure><A CLASS="TITLE" NAME="JNUT2-CH-10-FIG-3">Figure 10.3: The customizer dialog for the YesNoDialog bean</A></h4>


<p>
<img align=middle src="./figs/jn2_1003.gif" alt="[Graphic: Figure 10-3]" width=464 height=253 border=0>

</DIV>

<DIV CLASS=example>
<h4 CLASS=example><A CLASS="TITLE" NAME="JNUT2-CH-10-EX-8">Example 10.8: The YesNoDialogCustomizer Class</A></h4>

<DIV CLASS=screen>
<P>
<PRE>
package oreilly.beans.yesno;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
/**
 * This class is a customizer for the YesNoDialog bean.  It displays a
 * TextArea and three TextFields where the user can enter the dialog message
 * and the labels for each of the three buttons.  It does not allow the
 * dialog title or other resources to be set.
 */
public class YesNoDialogCustomizer extends Panel
                                   implements Customizer, TextListener
{
  protected YesNoDialog bean;                 // The bean being customized.
  protected TextComponent message, fields[];  // Components used by customizer
  // Default constructor: YesNoDialogCustomizer() { super(); }
  // The bean box calls this method to tell us what object to customize.
  // This method will always be called before the customizer is displayed,
  // so it is safe to create the customizer GUI here.
  public void setObject(Object o) {
    bean = (YesNoDialog)o;   // Save the object we're customizing.
    // Put a label at the top of the panel.
    this.setLayout(new BorderLayout());
    this.add(new Label("Enter the message to appear in the dialog:"), "North");
    // And a big text area below it for entering the dialog message.
    message = new TextArea(bean.getMessage());
    message.addTextListener(this);
    // TextAreas don't know how big they want to be.  You must tell them.
    message.setSize(400, 200);
    this.add(message, "Center");
    // Then add a row of textfields for entering the button labels.
    Panel buttonbox = new Panel();                     // The row container.
    buttonbox.setLayout(new GridLayout(1, 0, 25, 10)); // Equally spaced items.
    this.add(buttonbox, "South");                      // Put row on bottom.
    // Now go create three TextFields to put in this row.  But actually
    // position a Label above each, so create a container for each
    // TextField+Label combination.
    fields = new TextComponent[3];           // Array of TextFields.
    String[] labels = new String[] {         // Labels for each.
      "Yes Button Label", "No Button Label", "Cancel Button Label"};
    String[] values = new String[] {         // Initial values of each.
      bean.getYesLabel(), bean.getNoLabel(), bean.getCancelLabel()};
    for(int i = 0; i &lt; 3; i++) {
      Panel p = new Panel();                 // Create a container.
      p.setLayout(new BorderLayout());       // Give it a BorderLayout.
      p.add(new Label(labels[i]), "North");  // Put a label on the top.
      fields[i] = new TextField(values[i]);  // Create the text field.
      p.add(fields[i], "Center");            // Put it below the label.
      fields[i].addTextListener(this);       // Set the event listener.
      buttonbox.add(p);                      // Add container to row.
    }
  }
  // Add some space around the outside of the panel.
  public Insets getInsets() { return new Insets(10, 10, 10, 10); }
  // This is the method defined by the TextListener interface.  Whenever the
  // user types a character in the TextArea or TextFields, this will get
  // called.  It updates the appropriate property of the bean and fires a
  // property changed event, as all customizers are required to do.
  // Note that we are not required to fire an event for every keystroke.
  // Instead we could include an "Apply" button that would make all the
  // changes at once, with a single property changed event.
  public void textValueChanged(TextEvent e) {
    TextComponent t = (TextComponent)e.getSource();
    String s = t.getText();
    if (t == message) bean.setMessage(s);
    else if (t == fields[0]) bean.setYesLabel(s);
    else if (t == fields[1]) bean.setNoLabel(s);
    else if (t == fields[2]) bean.setCancelLabel(s);
    listeners.firePropertyChange(null, null, null);
  }
  // This code uses the PropertyChangeSupport class to maintain a list of
  // listeners interested in the edits we make to the bean.
  protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
  public void addPropertyChangeListener(PropertyChangeListener l) {
    listeners.addPropertyChangeListener(l);
  }
  public void removePropertyChangeListener(PropertyChangeListener l) {
    listeners.removePropertyChangeListener(l);
  }
}
</PRE>
</DIV>

</DIV>

</DIV>


<DIV CLASS=htmlnav>

<P>
<HR align=left width=515>
<table width=515 border=0 cellpadding=0 cellspacing=0>
<tr>
<td width=172 align=left valign=top><A HREF="ch10_07.htm"><IMG SRC="gifs/txtpreva.gif" ALT="Previous" border=0></A></td>
<td width=171 align=center valign=top><a href="index.htm"><img src='gifs/txthome.gif' border=0 alt='Home'></a></td>
<td width=172 align=right valign=top><A HREF="ch10_09.htm"><IMG SRC="gifs/txtnexta.gif" ALT="Next" border=0></A></td>
</tr>
<tr>
<td width=172 align=left valign=top>Defining a Complex Property Editor</td>
<td width=171 align=center valign=top><a href="index/idx_0.htm"><img src='gifs/index.gif' alt='Book Index' border=0></a></td>
<td width=172 align=right valign=top>Naming Patterns and Conventions</td>
</tr>
</table>
<hr align=left width=515>

<IMG SRC="gifs/smnavbar.gif" USEMAP="#map" BORDER=0> 
<MAP NAME="map"> 
<AREA SHAPE=RECT COORDS="0,0,108,15" HREF="../javanut/index.htm"
alt="Java in a Nutshell"> 
<AREA SHAPE=RECT COORDS="109,0,200,15" HREF="../langref/index.htm" 
alt="Java Language Reference"> 
<AREA SHAPE=RECT COORDS="203,0,290,15" HREF="../awt/index.htm" 
alt="Java AWT"> 
<AREA SHAPE=RECT COORDS="291,0,419,15" HREF="../fclass/index.htm" 
alt="Java Fundamental Classes"> 
<AREA SHAPE=RECT COORDS="421,0,514,15" HREF="../exp/index.htm" 
alt="Exploring Java"> 
</MAP>
</DIV>

</BODY>
</HTML>
